﻿ 

namespace Common.Algorithm.Core;

public class NSGAIIRealService
{
    #region data
    /// <summary>
    /// 随机数生成器
    /// </summary>
    private static Random randomBuilder = new Random();

    /// <summary>
    /// 交叉数量 一般为总数一般
    /// </summary>
    public int crossoverNum { get; set; } = 30;

    /// <summary>
    /// 编译数量 一般为种群的 1/10
    /// </summary>
    public int mutationNum { get; set; } = 5;

    /// <summary>
    /// 种群总数
    /// </summary>
    public int populationSize { get; set; } = 100;

    /// <summary>
    /// 目标函数  一般就是适应度函数
    /// </summary> 
    public List<Func<double[], double>> targetFuncs { get; set; }
    public List<double[]> ranges { get; set; } = new List<double[]>();
    public Func<int[], double[]> decodeFunc { get; set; }

    public static List<double[]> records = new List<double[]>();

    /// <summary>
    /// 种群总的基因表
    /// </summary>
    public static List<Sequence> sequences = new List<Sequence>();

    /// <summary>
    /// 基因链长度
    /// </summary>
    public static int sequenceLen { get; set; } = 2;

    /// <summary>
    /// 最佳基因暂存
    /// </summary>
    public static Sequence bestSequence { get; set; }

    #endregion

    public NSGAIIRealService(List<Func<double[], double>> _targetFuncs, List<double[]> _ranges)
    {
        targetFuncs = _targetFuncs;
        ranges = _ranges;
        crossoverNum = populationSize / 2;
        mutationNum = populationSize / 10;
        bestSequence = new Sequence(sequenceLen);

        sequences.Clear();
        //建立群
        for (int i = 0; i < populationSize; i++)
        {
            List<double> values = new List<double>();
            for (int j = 0; j < sequenceLen; j++)
            {
                var range = ranges[j];
                var value = range.First() + randomBuilder.NextDouble() * (range.Last() - range.First());
                values.Add(value);
            }
            var sequence = new Sequence(values);
            sequences.Add(sequence);
        }
    }

    public void RunAlgm(int numberOfGeneration)
    {
        while (numberOfGeneration > 0)
        {
            numberOfGeneration--;
            List<Sequence> childs = new List<Sequence>();
            for (int i = 0; i < crossoverNum; i++)
            {
                var father = sequences[randomBuilder.Next(sequences.Count)];
                var mother = sequences[randomBuilder.Next(sequences.Count)];
                var children = father.Crossover(mother, ranges);
                //if (child.Count() != sequenceLen) continue;//染色体数量变化  定义为其他物种 不计入种群
                childs.AddRange(children);
            }

            //sequences = sequences.Concat(childs).ToList();
            //Console.WriteLine(sequences.GroupBy(s => s.guid).Count());
            //Console.WriteLine(sequences.GroupBy(s => s.genes).Count());

            List<Sequence> mutates = new List<Sequence>();
            Parallel.For(0, mutationNum, (item) =>
            {
                var mutate = sequences[randomBuilder.Next(sequences.Count)];
                mutate = mutate.Mutation(ranges);
                if (mutate.Count() == sequenceLen)  //染色体数量变化  定义为其他物种 不计入种群
                    mutates.Add(mutate);
            });

            sequences = sequences.Concat(childs).Concat(mutates).ToList();

            Console.WriteLine(sequences.GroupBy(s => s.guid).Count());
            Console.WriteLine(sequences.GroupBy(s => s.genes).Count());

            sequences = Selection(sequences).ToList();

            foreach (var sequence in sequences)
            {
                var doubles = sequence;
                Console.WriteLine($"{doubles[0]},{doubles[1]}\t|");
                Console.WriteLine($"FUNC__{sequence.Fitness(targetFuncs[0])}\t|");
                Console.WriteLine($"FUNC__{sequence.Fitness(targetFuncs[1])}\t|");
                records.Add((new List<double>()
                        { doubles[0], doubles[1],
                        sequence.Fitness(targetFuncs[0]),
                        sequence.Fitness(targetFuncs[1])
                    }).ToArray());
            }
        }
        bestSequence = sequences.First();
    }

    public IList<Sequence> Selection2(IList<Sequence> sequences)
    {
        sequences.ToList().ForEach(s => s.rank = 0);
        sequences.ToList().ForEach(s => s.domindSeq.Clear());

        foreach (var sequence in sequences)
        {
            var curGenes = sequence.genes;
            //所有目标都比不过当前序列者  进行rank和支配操作
            sequences
                .Where(s => s != sequence)
                .Where(s => targetFuncs.All(func => func(curGenes) < func(s.genes)))
                .ToList().ForEach(s =>
                {
                    s.domindSeq.Add(sequence.guid);
                    s.rank += 1;
                });
        }

        var newSeqs = new List<Sequence>();
        int addedSize = 0;
        for (int i = 0; i < sequences.Max(s => s.rank) + 1; i++)
        {
            var paretoSeqs = sequences.Where(s => s.rank == i).ToList();
            if (paretoSeqs.Count == 0) continue;

            if (addedSize + paretoSeqs.Count < populationSize)
            {
                newSeqs.AddRange(paretoSeqs);
                addedSize += paretoSeqs.Count;
            }
            else
            {
                var size = populationSize - addedSize;
                var goodSeqs = CrowdDistance(paretoSeqs).ToList();
                newSeqs.AddRange(goodSeqs.GetRange(0, size));
                break;
            }
        }
        return newSeqs.GetRange(0, populationSize);

    }
    public IList<Sequence> Selection(IList<Sequence> sequences)
    {
        sequences.ToList().ForEach(s => s.rank = 0);
        sequences.ToList().ForEach(s => s.domindSeq.Clear());

        foreach (var sequence in sequences)
        {
            var curGenes = sequence.genes;
            //所有目标都比不过当前序列者  进行rank和支配操作
            sequences
                .Where(s => s != sequence)
                .Where(s => targetFuncs.All(func => func(curGenes) < func(s.genes)))
                .ToList().ForEach(s =>
                {
                    s.domindSeq.Add(sequence.guid);
                    s.rank += 1;
                });
        }

        var newSeqs = new List<Sequence>();
        var remainSeqs = sequences.ToList();
        int addedSize = 0;
        while (true)
        {
            var paretoSeqs = remainSeqs.Where(s => s.rank == 0).ToList();
            paretoSeqs.ForEach(ps => remainSeqs.Remove(ps));
            if (addedSize + paretoSeqs.Count < populationSize)
            {
                remainSeqs.ForEach(rs =>
                {
                    paretoSeqs.ForEach(ps => rs.domindSeq.Remove(ps.guid));
                    rs.rank -= 1;
                });
                newSeqs.AddRange(paretoSeqs);
                addedSize += paretoSeqs.Count;
            }
            else
            {
                var size = populationSize - addedSize;
                var goodSeqs = CrowdDistance(paretoSeqs).ToList();
                newSeqs.AddRange(goodSeqs.GetRange(0, size));
                break;
            }
        }

        //Console.WriteLine(sequences.GroupBy(s => s.guid).Count());
        //Console.WriteLine(sequences.GroupBy(s => s.genes).Count());
        //var paras = string.Join("\n", sequences.GroupBy(s => s.genes).Select(g => string.Join(",", g.First().genes)));
        //Console.WriteLine(paras);
        //var crods = string.Join("\n", sequences.Select(s => s.crowd));
        //Console.WriteLine(crods);

        return newSeqs.GetRange(0, populationSize);

    }

    public IList<Sequence> CrowdDistance(List<Sequence> sequences)
    {
        sequences.ForEach(s => s.crowd = 0);

        foreach (var targetFunc in targetFuncs)
        {
            var seqs = sequences
                .OrderBy(s => s.Fitness(targetFunc))
                .Select(s => new Tuple<Guid, double>(s.guid, s.Fitness(targetFunc))).ToList();
            var range = seqs.Max(selector => selector.Item2) - seqs.Min(selector => selector.Item2);

            sequences[0].crowd = double.MaxValue;
            sequences[sequences.Count - 1].crowd = double.MaxValue;

            for (int i = 1; i < sequences.Count - 1; i++)
            {
                sequences[i].crowd += (seqs[i + 1].Item2 - seqs[i - 1].Item2) / range;
            }
        }
        return sequences.OrderByDescending(s => s.crowd).ToList();
    }

    //==============================================================

    public class Sequence : IEnumerable<double>
    {
        private static Random randomBuilder = new Random();

        public Guid guid { get; set; } = Guid.NewGuid();

        public double[] genes { get; set; }

        /// <summary>
        /// 坐在支配阶级 0 1 2 3 为被多少人支配
        /// </summary>
        public int rank { get; set; }
        /// <summary>
        /// 当前领导数量
        /// </summary>
        public HashSet<Guid> domindSeq { get; set; } = new HashSet<Guid>();

        /// <summary>
        /// 拥挤度
        /// </summary>
        public double crowd { get; set; } = 0;

        /// <summary>
        /// 索引器
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public double this[int key]
        {
            get
            {
                return genes[key];
            }
            set
            {
                genes[key] = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="length"></param>
        public Sequence(int length)
        {
            this.genes = new double[length];
        }
        public Sequence(List<double> ints)
        {
            this.genes = ints.Select(g => g).ToArray();
        }
        public Sequence(double[] genes)
        {
            this.guid = Guid.NewGuid();
            this.genes = genes.Select(g => g).ToArray();
        }

        public IEnumerator<double> GetEnumerator()
        {
            foreach (var gene in genes)
                yield return gene;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public int Count()
        {
            return genes.Length;
        }

        /// <summary>
        /// 随机变异
        /// </summary>
        /// <param name="_num">变异的基因数量</param>
        /// <returns></returns>
        public Sequence Mutation(List<double[]> ranges)
        {
            var newSeq = new Sequence(this.genes);
            for (int i = 0; i < newSeq.Count(); i++)
            {
                var range = ranges[i];
                var span = range.Last() - range.First();
                //var tmp = (randomBuilder.NextDouble() - 0.5) * 0.01 * span;
                newSeq[i] = range.First() + randomBuilder.NextDouble() * span;
                //genes[i] += tmp;
                //genes[i] = Math.Min(range.Last(), genes[i]);
                //genes[i] = Math.Max(range.First(), genes[i]);
            }
            return newSeq;
        }

        /// <summary>
        /// 交叉交换基因
        /// </summary>
        /// <param name="pattern">对方</param>
        /// <param name="_num">交换染色体数量</param>
        /// <returns></returns>
        public Sequence[] Crossover(Sequence pattern, List<double[]> ranges)
        {
            var childSeq1 = new Sequence(this.genes);
            var childSeq2 = new Sequence(this.genes);

            for (int i = 0; i < this.genes.Count(); i++)
            {
                var range = ranges[i];
                var span = range.Last() - range.First();
                var crossFactor = randomBuilder.NextDouble();

                //子代1号
                childSeq1[i] = crossFactor * this[i] + (1 - crossFactor) * pattern[i];
                //超范围后轮询定位  超出最大值x 回到开头加x位置   取值范围是个循环链表   
                //if (childSeq1[i] > range.Last()) childSeq1[i] = range.First() + Math.Abs(childSeq1[i] - range.Last());
                //if (childSeq1[i] < range.First()) childSeq1[i] = range.Last() - Math.Abs(childSeq1[i] - range.First());
                //超范围后随机定位 
                if (childSeq1[i] > range.Last() ||
                    childSeq1[i] < range.First())
                    childSeq1[i] = range.First() + crossFactor * span;

                //子代2号
                childSeq2[i] = crossFactor * pattern[i] + (1 - crossFactor) * this[i];
                //超范围后轮询定位  超出最大值x 回到开头加x位置   取值范围是个循环链表   
                //if (childSeq2[i] > range.Last()) childSeq2[i] = range.First() + Math.Abs(childSeq2[i] - range.Last());
                //if (childSeq2[i] < range.First()) childSeq2[i] = range.Last() - Math.Abs(childSeq2[i] - range.First());
                //超范围后随机定位 
                if (childSeq2[i] > range.Last() ||
                    childSeq2[i] < range.First())
                    childSeq2[i] = range.First() + crossFactor * span;

            }
            return new Sequence[] { childSeq1, childSeq2 };
        }

        /// <summary>
        /// 适应度函数
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        public double Fitness(Func<double[], double> func)
        {
            return func(genes);
        }

        //public double Fitness(Func<double[], double> func, Func<double[], double[]> decodeFunc)
        //{
        //    return func(decodeFunc(genes));
        //}

        public double[] Decode(Func<double[], double[]> decodeFunc)
        {
            return decodeFunc(genes);
        }


    }
}


